using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

[CreateAssetMenu(fileName = "Pool", menuName = "Assets/ObjectPool")]
public class ObjectPool : ScriptableObject
{
    public string poolName;
    public List<ObjectPoolItem> itemList;
    [HideInInspector]public Transform tran;
    private Dictionary<string, ObjectPoolItem> objectDict;

    private ObjectPoolSystem objectPoolSystem;
    public ObjectPool()
    {
        itemList = new List<ObjectPoolItem>(); 
        objectDict = new Dictionary<string, ObjectPoolItem>();
    }
    public void Init(Transform transform)
    {
        objectPoolSystem = ObjectPoolSystem.Instance;
        tran = transform;
        
        foreach (ObjectPoolItem item in itemList)
        {
            objectDict.Add(item.itemName, item.GetCopy());
            FillPool(item.itemName);
        }
    }
    public GameObject CreateObjectPoolItemAndReturnGO(string itemName, int queueSize, GameObject go)
    {
        objectDict.Add(itemName, new ObjectPoolItem(itemName, queueSize, go));
        FillPool(itemName);
        return GetFromPool(itemName);
    }

    public void FillPool(string itemName)
    {
        ObjectPoolItem opi = null;
        if (objectDict.TryGetValue(itemName, out opi))
        {
            for (int i = 0; i < opi.queueSize; i++)
            {
                GameObject o = objectPoolSystem.CreateGO(opi.go, tran);
                o.GetComponent<IPoolObject>().Init(poolName, itemName);
                opi.objectQueue.Enqueue(o);
            }
            opi.queueSize *= 2;
        }
    }
    public GameObject GetFromPool(string itemName)
    {
        ObjectPoolItem opi = null;
        if (objectDict.TryGetValue(itemName, out opi))
        {
            if (opi.objectQueue.Count > 0)
            {
                return opi.objectQueue.Dequeue();
            }
            else
            {
                FillPool(opi.itemName);
                return opi.objectQueue.Dequeue();
            }
        }
        return null;
    }
    public void BackToPool(string itemName,GameObject o)
    {
        ObjectPoolItem opi = null;
        if (objectDict.TryGetValue(itemName, out opi))
        {
            if (opi.objectQueue.Count == opi.queueSize)
            {
                Destroy(o);
            }
            else
            {
                opi.objectQueue.Enqueue(o);
            }
        }
    }
}

[Serializable]
public class ObjectPoolItem
{
    public string itemName;
    public int queueSize;
    public GameObject go;
    public Queue<GameObject> objectQueue;
    public ObjectPoolItem() { }
    public ObjectPoolItem(string itemName, int queueSize, GameObject go)
    {
        this.itemName = itemName;
        this.queueSize = queueSize;
        this.go = go;
        this.objectQueue = new Queue<GameObject>();
    }
    public ObjectPoolItem GetCopy()
    {
        return new ObjectPoolItem(this.itemName, this.queueSize, this.go);
    }
}
